TuringMachine = function (tape, rulesTable, initialCursor) {
    this._tape = tape;
    this._rulesTable = rulesTable;
    this._cursor = typeof(initialCursor) === 'undefined' ? 0 : initialCursor;
    this._currentState = rulesTable.getInitialState();
    this._currentStep = 0;
};

TuringMachine.prototype = {
    nextStep:function () {
        if (this._currentState.isHaltState()) {
            return false;
        }
        ++this._currentStep;
        var symbol = this._tape.getSymbol(this._cursor);
        var rule = this._currentState.getRule(symbol);
        this._tape.setSymbol(this._cursor, rule.getSymbolToWrite());
        this._currentState = this._rulesTable.getState(rule.getTargetStateName());
        this._cursor += rule.getMoveType() === Rule.MoveType.LEFT ? -1 : 1;
        return true;
    },

    isHalted:function () {
        return this._currentState.isHaltState();
    },

    getStates:function () {
        return this._rulesTable.getStates();
    },

    getStatesInOrder: function() {
        return this._rulesTable.getStatesInOrder();
    },

    getAlphabet:function () {
        return this._tape.getAlphabet();
    },

    getCursor:function () {
        return this._cursor;
    },

    getTape:function () {
        return this._tape;
    },

    getCurrentState:function () {
        return this._currentStep;
    },

    hasState:function (stateName) {
        var states = this.getStates();
        for (i in states) {
            var state = states[i];
            if (state.getName() === stateName)
                return true;
        }
        return false;
    },

    addState:function (stateName, alphabet, rules) {
        this._rulesTable.addState(stateName, alphabet, rules);
    },

    removeState:function (stateName) {
        this._rulesTable.removeState(stateName, this.getAlphabet());
    },

    setCurrentState:function (state) {
        this._currentState = state;
    },

    reset:function (tape, initialCursor) {
        this._currentStep = 0;
        this._cursor = initialCursor;
        this._tape = tape;
        this._currentState = this._rulesTable.getInitialState();
    }
};
